#include <sys/stat.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>

#define MK_BIN_FILE_NAME_MAX 30
#define BOOTLOAD_FILE_OFFSET    0X1000
#define APP_FILE_OFFSET         0X10000
#define PARTATION_FILE_OFFSET   0X8000
#define FACTORY_FILE_OFFSET     0X730000

int copy_data(int dtsfd,int srcfd,int type)
{
    int len;
    long long i=0;
    int ret;
    char fillbuff[4096];
    char buff[4096];
    memset(buff,0,sizeof(buff));
    memset(fillbuff,0xff,sizeof(fillbuff));
    switch(type){
        //bootloader
        case 1:
            if(lseek(dtsfd,BOOTLOAD_FILE_OFFSET,SEEK_SET)!=BOOTLOAD_FILE_OFFSET){
                printf("lseek error\n");
                return -1;
            }
            while((len=read(srcfd,buff,4096))!=0){
                if((int)(write(dtsfd,buff,len))!=len){
                    printf("write error\n");
                    return -1;
                }
            }
            if(len==-1){
                printf("read error\n");
                return -1;
            }
            break;
        //app
        case 2:
            if(lseek(dtsfd,APP_FILE_OFFSET,SEEK_SET)!=APP_FILE_OFFSET){
                printf("lseek error\n");
                return -1;
            }
            while((len=read(srcfd,buff,4096))!=0){
                if((int)(write(dtsfd,buff,len))!=len){
                    printf("write error\n");
                    return -1;
                }
            }
            if(len==-1){
                printf("read error\n");
                return -1;
            }
            break;
        //partation
        case 3:
            if(lseek(dtsfd,PARTATION_FILE_OFFSET,SEEK_SET)!=PARTATION_FILE_OFFSET){
                printf("lseek error\n");
                return -1;
            }
            while((len=read(srcfd,buff,4096))!=0){
                if((int)(write(dtsfd,buff,len))!=len){
                    printf("write error\n");
                    return -1;
                }
            }
            if(len==-1){
                printf("read error\n");
                return -1;
            }
            break;
        //factory
        case 4:
            //填充0XFF
            for(i=0;i<FACTORY_FILE_OFFSET;i+=4096){
                if((int)(write(dtsfd,fillbuff,4096))!=4096){
                    printf("write error\n");
                    return -1;
                }
            }
            if(lseek(dtsfd,FACTORY_FILE_OFFSET,SEEK_SET)!=FACTORY_FILE_OFFSET){
                printf("lseek error\n");
                return -1;
            }
            while((len=read(srcfd,buff,4096))!=0){
                if((int)(write(dtsfd,buff,len))!=len){
                    printf("write error\n");
                    return -1;
                }
            }
            if(len==-1){
                printf("read error\n");
                return -1;
            }
            break;
        default:
            return -1;
            break;
    }
    return 0;
}

int mkbin(char *dtsfilename,char * bootloader_file,char *app_file,char *partition_file,char *factory_file)
{
    int dtsfd,bootfd,appfd,partfd,factoryfd;
    dtsfd=open(dtsfilename,O_RDWR|O_CREAT,S_IRWXU);
    if(dtsfd==-1){
        printf("open dtsfilename is error\n");
        return -1;
    }
    //要先拷贝factory文件
    factoryfd=open(factory_file,O_RDONLY);
    if(factoryfd==-1){
        close(factoryfd);
        printf("open factory_file is error\n");
        return -1;
    }
    //拷贝factory
    if(copy_data(dtsfd,factoryfd,4)!=0){
        close(dtsfd);
        close(factoryfd);
        printf("copy factory_file is error\n");
        return -1;
    }
    close(factoryfd);
    //打开boot文件
    bootfd=open(bootloader_file,O_RDONLY);
    if(bootfd==-1){
        close(dtsfd);
        printf("open bootloader_file is error\n");
        return -1;
    }
    //拷贝bootloader
    if(copy_data(dtsfd,bootfd,1)!=0){
        close(dtsfd);
        close(bootfd);
        printf("copy bootloader_file is error\n");
        return -1;
    }
    close(bootfd);
    //打开app文件
    appfd=open(app_file,O_RDONLY);
    if(appfd==-1){
        close(dtsfd);
        printf("open app_file is error\n");
        return -1;
    }
    //拷贝app文件
    if(copy_data(dtsfd,appfd,2)!=0){
        close(dtsfd);
        close(appfd);
        printf("copy app_file is error\n");
        return -1;
    }
    close(appfd);
    //打开partation文件
    partfd=open(partition_file,O_RDONLY);
    if(partfd==-1){
        close(dtsfd);
        printf("open partition_file is error\n");
        return -1;
    }
    //拷贝partation文件
    if(copy_data(dtsfd,partfd,3)!=0){
        close(dtsfd);
        close(partfd);
        printf("copy partition_file is error\n");
        return -1;
    }
    close(dtsfd);
    close(partfd);
    printf("copy all is success\n");
    return 0;   
}
/**
 * -b bootloader文件
 * -a app文件
 * -p 分区表文件
 * -f 出厂文件
 */ 
int main(int argc, char * argv[])
{
    int ch;
    char mkfilename[MK_BIN_FILE_NAME_MAX];
    char app_file[MK_BIN_FILE_NAME_MAX];
    char bootloader_file[MK_BIN_FILE_NAME_MAX];
    char partition_file[MK_BIN_FILE_NAME_MAX];
    char factory_file[MK_BIN_FILE_NAME_MAX];
    int is_get_app_file=0;
    int is_get_bootloader_file=0;
    int is_get_partition_file=0;
    int is_get_factory_file=0;
    int is_get_mkfilename=0;
    //初始化变量
    memset(mkfilename,0,MK_BIN_FILE_NAME_MAX);
    memset(app_file,0,MK_BIN_FILE_NAME_MAX);
    memset(bootloader_file,0,MK_BIN_FILE_NAME_MAX);
    memset(partition_file,0,MK_BIN_FILE_NAME_MAX);
    memset(factory_file,0,MK_BIN_FILE_NAME_MAX);

    while ((ch = getopt(argc, argv, "a:b:p:f:d:")) != -1){
        printf("optind: %d\n", optind);
        switch (ch) 
        {
            case 'a':
                printf("app file name: %s\n",optarg);
                is_get_app_file=1;
                memcpy(app_file,optarg,strlen(optarg));
                break;
            case 'b':
                printf("bootloader file name: %s\n",optarg);
                is_get_bootloader_file=1;
                memcpy(bootloader_file,optarg,strlen(optarg));   
                break;
            case 'p':
                printf("partition file name: %s\n",optarg);
                is_get_partition_file=1;
                memcpy(partition_file,optarg,strlen(optarg));  
                break;
            case 'f':
                printf("factory file name: %s\n",optarg);
                is_get_factory_file=1;
                memcpy(factory_file,optarg,strlen(optarg));   
                break;
            case 'd':
                printf("mkfilename file name: %s\n",optarg);
                is_get_mkfilename=1;
                memcpy(mkfilename,optarg,strlen(optarg));    
                break;
            case '?':
                printf("Unknown option: %c\n",(char)optopt);
                break;
        }
    }
    
    if(is_get_bootloader_file==0){
        printf("bootloader file name is null,agrv is -b\n");
        return -1;
    }
    if(is_get_app_file==0){
        printf("app file name is null,agrv is -a\n");
        return -1;
    }
    if(is_get_partition_file==0){
        printf("partition file name is null,agrv is -p\n");
        return -1;
    }
    if(is_get_factory_file==0){
        printf("factory file name is null,agrv is -f\n");
        return -1;
    }
    if(is_get_mkfilename==0){
        printf("mkfile file name is null,agrv is -d\n");
        return -1;
    }
    //开始执行二进制文件拷贝
    return mkbin(mkfilename,bootloader_file,app_file,partition_file,factory_file);

}
